/**
 * Copyright (c) 2015-2018 iqiyi
 * All rights reserved.
 *
 * Author     : Wang Haibin
 * E-mail     : wanghaibin@qiyi.com
 * Version    :
 * Date       : Fri 20 Nov 2020 11:48:06 AM CST
 * Destription: 引用模板类
 */
#ifndef IQDB_REF_H
#define IQDB_REF_H

#include "stdafx.h"

//using namespace IQDB;
//namespace IQDB {

template <class type>
class iqdb_reference
{

public:
    iqdb_reference () : p_(NULL) {
    }

    iqdb_reference (const type *p) : p_(p) {
        printf("call iqdb_reference (const type *p)\n");
        reference (*this);
    }

    ~iqdb_reference() {
        printf("call %s\n", __func__);
        dereference();
    }

    iqdb_reference (const iqdb_reference &p) : p_(p.p_) {
        printf("call iqdb_reference (const iqdb_reference &p)\n");
        reference (p);
    }

#if __cplusplus >= 201103L
    iqdb_reference (iqdb_reference &&p) : p_(std::move(p.p_)) {
        p.p_=NULL;
    }
#endif

    iqdb_reference& operator = (const iqdb_reference& p) {
        printf("call operator =\n");
        // 注意不要修改顺序，
        const type *newP_ = p.p_;
        reference(p);
        dereference(newP_);
        return *this;
    }

#if __cplusplus >= 201103L
    iqdb_reference& operator = (iqdb_reference&& p) {
        if (this != &p) {
            dereference(p.p_);
            p.p_ = NULL;
        }
        return *this;
    }
#endif
    //explicit operator bool() const { return p_; }

    bool operator !() const {return !p_; }

    type * operator-> () const {return const_cast<type *>(p_); }

    type & operator * () const {
        assert(p_);
        return *const_cast<type *>(p_);
    }

    /**
     * 获取原始内容指针
     */
    type * get_raw() const { return const_cast<type *>(p_); }

    bool operator == (const iqdb_reference& p) const {
        return p.p_ == p_;
    }

    bool operator != (const iqdb_reference &p) const {
        return p.p_ != p_;
    }

private:
    void dereference(const type *newP = NULL) {
        // 注意要先设置临时的p_指针，可能已经调用 delete 销毁自己
        //type const (*tempP_) (p_);
        const type * tempP_ = p_;
        p_ = newP;
        if (tempP_ && tempP_->dereference()==0) {
            delete tempP_;
        }
    }

    void reference (const iqdb_reference& p) {
        if (p.p_) {
            printf("add ref=\n");
            p.p_->reference();
        }
    }

private:
    const type *p_;
};

// /* IQDB  */

#endif
